﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GraphViewer.Entity;
using GraphViewer.View;
using System.IO;
using System.Diagnostics;
using System.Configuration;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml;
using GraphViewer.Data;
using System.Threading.Tasks;
using System.Threading;

namespace GraphViewer
{
    public class ExecutionProcess
    {
        public int ExitCode { get; set; }

        private StringBuilder _messageBuilder;
        private string _mtsServerName;
        private string _dataBase;
        private ProcessEntity _process;
        private bool _schedule;
        private CancellationTokenSource _tokenSource;

        public ExecutionProcess(ProcessEntity process, string mtsServerName, string dataBase, bool schedule, CancellationTokenSource tokenSource)
        {
            _mtsServerName = mtsServerName;
            _dataBase = dataBase;
            _process = process;
            _schedule = schedule;
            _tokenSource = tokenSource;
        }

        public void Execute(Task[] tasks)
        {
            Execute();
        }

        public void Execute2()
        {
            try
            {
                int id = 0;

                ProcessEntity processFound = ExecutionControl.Instance.GetProcesses(_process.GroupId).Find(pr => pr.ProcessId == _process.ProcessId);

                if (!int.TryParse(_process.ProcessId, out id) || processFound != null)
                {
                    ExitCode = 0;
                    return;
                }

                Console.WriteLine("Executando Processo: " + _process.ProcessId.ToString() + " do Grupo: " + _process.GroupId.ToString());

                if (_tokenSource.IsCancellationRequested)
                    _tokenSource.Token.ThrowIfCancellationRequested();

                Thread.Sleep(1);

                if (_process.ProcessId == ExecutionControl.Instance.ProcessForceError)
                    throw new UnauthorizedAccessException();

                ExecutionControl.Instance.AddProcess(_process.GroupId, _process);
                ExecutionControl.Instance.Save(_process.GroupId);

                ExitCode = 0;
            }
            catch (Exception ex)
            {
                Console.WriteLine(System.Environment.NewLine);
                Console.WriteLine("     Problema no processo: " + _process.ProcessId.ToString() + " do Grupo: " + _process.GroupId.ToString());
                Console.WriteLine(ex.ToString());
                
                ExecutionControl.Instance.Log(_process.GroupId, _process.ProcessId, ex.ToString());

                _tokenSource.Cancel();

                throw;
            }
        }

        public void Execute()
        {
            try
            {
                int id = 0;

                ProcessEntity processFound = ExecutionControl.Instance.GetProcesses(_process.GroupId).Find(pr => pr.ProcessId == _process.ProcessId);

                if (!int.TryParse(_process.ProcessId, out id) || processFound != null)
                {
                    ExitCode = 0;
                    return;
                }

                if (!_schedule) Console.WriteLine("Executando Processo: " + _process.ProcessId.ToString() + " do Grupo: " + _process.GroupId.ToString());

                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.FileName = @"\\" + _mtsServerName + @"\Componentes\dotnet\SRC\ibba.src.console.exe";

                if (_schedule)
                {
                    p.StartInfo.Arguments = @"-servidor:" + _mtsServerName + " -tipo:agendar -sistema:1 -ref:" + _dataBase;
                }
                else
                {
                    p.StartInfo.Arguments = @"-servidor:" + _mtsServerName + " -tipo:comando -id:" + _process.ProcessId + " -ref:" + _dataBase;
                }

                p.StartInfo.CreateNoWindow = true;
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.RedirectStandardOutput = true;

                _messageBuilder = new StringBuilder();

                p.ErrorDataReceived += new DataReceivedEventHandler(p_ErrorDataReceived);
                p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);

                if (_tokenSource.IsCancellationRequested)
                    _tokenSource.Token.ThrowIfCancellationRequested();

                if (_process.ProcessId == ExecutionControl.Instance.ProcessForceError)
                    throw new UnauthorizedAccessException();

                p.Start();

                p.BeginOutputReadLine();
                p.BeginErrorReadLine();

                p.WaitForExit();

                if (p.ExitCode != 0)
                {
                    throw new Exception(_messageBuilder.ToString());
                }
                else
                {
                    ExecutionControl.Instance.AddProcess(_process.GroupId, _process);
                    ExecutionControl.Instance.Save(_process.GroupId);
                }

                ExitCode = p.ExitCode;
            }
            catch (Exception ex)
            {
                Console.WriteLine(System.Environment.NewLine);
                Console.WriteLine("     Problema no processo: " + _process.ProcessId.ToString() + " do Grupo: " + _process.GroupId.ToString());
                Console.WriteLine(ex.ToString());

                ExecutionControl.Instance.Log(_process.GroupId, _process.ProcessId, ex.ToString());

                _tokenSource.Cancel();

                throw;
            }
        }

        private void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            _messageBuilder.AppendLine(e.Data);
        }

        private void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {

        }
    }
}
